home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Modules / BackSpaceModules / Source / Polyhedra / PolyhedraView.m < prev    next >
Text File  |  1992-04-16  |  28KB  |  934 lines

  1. //
  2. // RegularPolyhedraView  -  a flexible, bouncing polyhedron.
  3. //
  4. // Module for BackSpace.app
  5. // 22 Nov 91 - 8 Dec 91.
  6. // Simon Marchant, and Paul Brown (simon@math.berkeley.edu,
  7. //        pbrown@math.berkeley.edu).
  8. //
  9.  
  10. #import "PolyhedraView.h"
  11. #import "PolyhedraViewWraps.h"
  12.  
  13. #import <appkit/graphics.h>
  14. #import <appkit/Matrix.h>
  15. #import <libc.h>
  16. #import <dpsclient/wraps.h>
  17. #import <math.h>
  18. #import <appkit/publicWraps.h>
  19.  
  20. // Number of vertices of the polyhedron
  21. static int theNumVertices[NUM_POLYHEDRA] =
  22.     {4, 8, 6, 20, 12};
  23.  
  24. // Number of vertices adjacent to a vertex.
  25. static int theNumAdjacents[NUM_POLYHEDRA] =
  26.     {3, 3, 4, 3, 5};
  27.  
  28. // Number of faces of the polyhedron.
  29. static int theNumFaces[NUM_POLYHEDRA] =
  30.     {4, 6, 8, 12, 20};
  31.  
  32. // Number of vertices on each face.
  33. static int theVerticesPerFace[NUM_POLYHEDRA] =
  34.     {3, 4, 3, 5, 3};
  35.  
  36. // Number of non NO_DRAW faces - i.e. faces that we actually bother drawing.
  37. static int realFaces[NUM_POLYHEDRA] =
  38.     {3, 4, 4, 9, 14};
  39.  
  40. // Numbers describing the 3D co-ordinates of the polyhedra - the initial positions.
  41. static D3_PT offsets[NUM_POLYHEDRA][MAX_NUM_VERTICES] = {
  42.    {{ 0,         0,         1.73205},    // Tetrahedron
  43.     { 0,         1.63299,  -0.57735},
  44.     {-1.41421,  -0.816497, -0.57735},
  45.     { 1.41421,  -0.816497, -0.57735},
  46.     { 0,         0,         0},
  47.     { 0,         0,         0},
  48.     { 0,         0,         0},
  49.     { 0,         0,         0},
  50.     { 0,         0,         0},
  51.     { 0,         0,         0},
  52.     { 0,         0,         0},
  53.     { 0,         0,         0},
  54.     { 0,         0,         0},
  55.     { 0,         0,         0},
  56.     { 0,         0,         0},
  57.     { 0,         0,         0},
  58.     { 0,         0,         0},
  59.     { 0,         0,         0},
  60.     { 0,         0,         0},
  61.     { 0,         0,         0}},
  62.    {{ 0.707107,  0.707107,  0.707107},    // Cube.
  63.     {-0.707107,  0.707107,  0.707107},
  64.     {-0.707107, -0.707107,  0.707107},
  65.     { 0.707107, -0.707107,  0.707107},
  66.     {-0.707107, -0.707107, -0.707107},
  67.     { 0.707107, -0.707107, -0.707107},
  68.     { 0.707107,  0.707107, -0.707107},
  69.     {-0.707107,  0.707107, -0.707107},
  70.     { 0,         0,         0},
  71.     { 0,         0,         0},
  72.     { 0,         0,         0},
  73.     { 0,         0,         0},
  74.     { 0,         0,         0},
  75.     { 0,         0,         0},
  76.     { 0,         0,         0},
  77.     { 0,         0,         0},
  78.     { 0,         0,         0},
  79.     { 0,         0,         0},
  80.     { 0,         0,         0},
  81.     { 0,         0,         0}},
  82.    {{ 0,         0,         1.41421},    // Octahedron
  83.     { 1.41421,   0,         0},
  84.     { 0,         1.41421,   0},
  85.     { 0,         0,        -1.41421},
  86.     {-1.41421,   0,         0},
  87.     { 0,        -1.41421,   0},
  88.     { 0,         0,         0},
  89.     { 0,         0,         0},
  90.     { 0,         0,         0},
  91.     { 0,         0,         0},
  92.     { 0,         0,         0},
  93.     { 0,         0,         0},
  94.     { 0,         0,         0},
  95.     { 0,         0,         0},
  96.     { 0,         0,         0},
  97.     { 0,         0,         0},
  98.     { 0,         0,         0},
  99.     { 0,         0,         0},
  100.     { 0,         0,         0},
  101.     { 0,         0,         0}},
  102.    {{ 0.525731,  0.381966,  0.850651},    //Dodecahedron.
  103.     {-0.200811,  0.618034,  0.850651},
  104.     {-0.649839,  0,         0.850651},
  105.     {-0.200811, -0.618034,  0.850651},
  106.     { 0.525731, -0.381966,  0.850651},
  107.     { 0.850651,  0.618034,  0.200811},
  108.     {-0.32492,   1.0,       0.200811},
  109.     {-1.05146,   0,         0.200811},
  110.     {-0.32492,  -1.0,       0.200811},
  111.     { 0.850651, -0.618034,  0.200811},
  112.     { 0.32492,   1.0,      -0.200811},
  113.     {-0.850651,  0.618034, -0.200811},
  114.     {-0.850651, -0.618034, -0.200811},
  115.     { 0.32492,  -1.0,      -0.200811},
  116.     { 1.05146,   0,        -0.200811},
  117.     { 0.200811,  0.618034, -0.850651},
  118.     {-0.525731,  0.381966, -0.850651},
  119.     {-0.525731, -0.381966, -0.850651},
  120.     { 0.200811, -0.618034, -0.850651},
  121.     { 0.649839,  0,        -0.850651}},
  122.    {{ 0,         0,         1.0},        // Icosahedron.
  123.     { 0.894427,  0,         0.447214},
  124.     { 0.276393,  0.850651,  0.447214},
  125.     {-0.723607,  0.525731,  0.447214},
  126.     {-0.723607, -0.525731,  0.447214},
  127.     { 0.276393, -0.850651,  0.447214},
  128.     { 0.723607,  0.525731, -0.447214},
  129.     {-0.276393,  0.850651, -0.447214},
  130.     {-0.894427,  0,        -0.447214},
  131.     {-0.276393, -0.850651, -0.447214},
  132.     { 0.723607, -0.525731, -0.447214},
  133.     { 0,         0,        -1.0},
  134.     { 0,         0,         0},
  135.     { 0,         0,         0},
  136.     { 0,         0,         0},
  137.     { 0,         0,         0},
  138.     { 0,         0,         0},
  139.     { 0,         0,         0},
  140.     { 0,         0,         0},
  141.     { 0,         0,         0}}};
  142.  
  143. // List of faces in the polyhedron.
  144. static int faces[NUM_POLYHEDRA][MAX_NUM_FACES][MAX_VERTICES_PER_FACE] = {
  145.     {{0, 1, 2, -1, -1},            // Tetrahedron.
  146.      {0, 2, 3, -1, -1},
  147.      {0, 3, 1, -1, -1},
  148.      {1, 3, 2, -1, -1},
  149.      {-1, -1, -1, -1, -1},
  150.      {-1, -1, -1, -1, -1},
  151.      {-1, -1, -1, -1, -1},
  152.      {-1, -1, -1, -1, -1},
  153.      {-1, -1, -1, -1, -1},
  154.      {-1, -1, -1, -1, -1},
  155.      {-1, -1, -1, -1, -1},
  156.      {-1, -1, -1, -1, -1},
  157.      {-1, -1, -1, -1, -1},
  158.      {-1, -1, -1, -1, -1},
  159.      {-1, -1, -1, -1, -1},
  160.      {-1, -1, -1, -1, -1},
  161.      {-1, -1, -1, -1, -1},
  162.      {-1, -1, -1, -1, -1},
  163.      {-1, -1, -1, -1, -1},
  164.      {-1, -1, -1, -1, -1}},
  165.     {{0, 1, 2, 3, -1},            // Cube.
  166.      {0, 3, 5, 6, -1},
  167.      {0, 6, 7, 1, -1},
  168.      {1, 7, 4, 2, -1}, 
  169.      {4, 7, 6, 5, -1},
  170.      {2, 4, 5, 3, -1},
  171.      {-1, -1, -1, -1, -1},
  172.      {-1, -1, -1, -1, -1},
  173.      {-1, -1, -1, -1, -1},
  174.      {-1, -1, -1, -1, -1},
  175.      {-1, -1, -1, -1, -1},
  176.      {-1, -1, -1, -1, -1},
  177.      {-1, -1, -1, -1, -1},
  178.      {-1, -1, -1, -1, -1},
  179.      {-1, -1, -1, -1, -1},
  180.      {-1, -1, -1, -1, -1},
  181.      {-1, -1, -1, -1, -1},
  182.      {-1, -1, -1, -1, -1},
  183.      {-1, -1, -1, -1, -1},
  184.      {-1, -1, -1, -1, -1}},
  185.     {{0, 1, 2, -1, -1},            // Octahedron.
  186.      {0, 2, 4, -1, -1},
  187.      {0, 4, 5, -1, -1},
  188.      {0, 5, 1, -1, -1},
  189.      {1, 5, 3, -1, -1},
  190.      {1, 3, 2, -1, -1},
  191.      {3, 5, 4, -1, -1},
  192.      {2, 3, 4, -1, -1},
  193.      {-1, -1, -1, -1, -1},
  194.      {-1, -1, -1, -1, -1},
  195.      {-1, -1, -1, -1, -1},
  196.      {-1, -1, -1, -1, -1},
  197.      {-1, -1, -1, -1, -1},
  198.      {-1, -1, -1, -1, -1},
  199.      {-1, -1, -1, -1, -1},
  200.      {-1, -1, -1, -1, -1},
  201.      {-1, -1, -1, -1, -1},
  202.      {-1, -1, -1, -1, -1},
  203.      {-1, -1, -1, -1, -1},
  204.      {-1, -1, -1, -1, -1}},
  205.     {{0, 1, 2, 3, 4},            // Dodecahedron.
  206.      {0, 4, 9, 14, 5},
  207.      {0, 5, 10, 6, 1},
  208.      {1, 6, 11, 7, 2},
  209.      {2, 7, 12, 8, 3},
  210.      {3, 4, 9, 13, 8},
  211.      {5, 14, 19, 15, 10},
  212.      {6, 10, 15, 16, 11},
  213.      {7, 11, 16, 17, 12},
  214.      {8, 12, 17, 18, 13},
  215.      {9, 13, 18, 19, 14},
  216.      {15, 19, 18, 17, 16},
  217.      {-1, -1, -1, -1, -1},
  218.      {-1, -1, -1, -1, -1},
  219.      {-1, -1, -1, -1, -1},
  220.      {-1, -1, -1, -1, -1},
  221.      {-1, -1, -1, -1, -1},
  222.      {-1, -1, -1, -1, -1},
  223.      {-1, -1, -1, -1, -1},
  224.      {-1, -1, -1, -1, -1}},
  225.     {{0, 2, 1, -1, -1},            // Icosahedron.
  226.      {0, 3, 2, -1, -1},
  227.      {0, 4, 3, -1, -1},
  228.      {0, 5, 4, -1, -1},
  229.      {0, 1, 5, -1, -1},
  230.      {1, 2, 6, -1, -1},
  231.      {2, 3, 7, -1, -1},
  232.      {3, 4, 8, -1, -1},
  233.      {4, 5, 9, -1, -1},
  234.      {5, 1, 10, -1, -1},
  235.      {6, 2, 7, -1, -1},
  236.      {7, 3, 8, -1, -1},
  237.      {8, 4, 9, -1, -1},
  238.      {9, 5, 10, -1, -1},
  239.      {10, 1, 6, -1, -1},
  240.      {6, 7, 11, -1, -1},
  241.      {7, 8, 11, -1, -1},
  242.      {8, 9, 11, -1, -1},
  243.      {9, 10, 11, -1, -1},
  244.      {10, 6, 11, -1, -1}}};
  245.  
  246. // Array following contains the vertex adjacency information, so we can 
  247. // determine which n vertices are adjacent to any given one.
  248.  
  249.  
  250. typedef struct { float r,g,b; } rgbcolor;
  251.  
  252. static rgbcolor clut[5] = {
  253.     {1,0,0},
  254.     {0,1,.2},
  255.     {0,0,1},
  256.     {1,.8,0},
  257.     {1,.3,0}
  258.     };
  259.     
  260. // Two "pseudo-colours".
  261. #define TRANSPARENT        -1
  262. #define NO_DRAW            -2
  263.  
  264. // Colour that you draw the face with.
  265. // TRANSPARENT means just draw the edges.
  266. // NO_DRAW means that the face is transparent, and other faces
  267. // draw all the edges of the face - so no need to draw it.
  268. static int faceColour[NUM_POLYHEDRA][MAX_NUM_FACES] =
  269.    {{0, TRANSPARENT, TRANSPARENT, NO_DRAW,
  270.      TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
  271.      TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
  272.      TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
  273.      TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT},
  274.     {1, NO_DRAW, TRANSPARENT, NO_DRAW,
  275.      2, TRANSPARENT, TRANSPARENT, TRANSPARENT,
  276.      TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
  277.      TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
  278.      TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT},
  279.     {3, NO_DRAW, 4, NO_DRAW,
  280.      0, NO_DRAW, NO_DRAW, 1,
  281.      TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
  282.      TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
  283.      TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT},
  284.     {2, NO_DRAW, TRANSPARENT, NO_DRAW,
  285.      TRANSPARENT, TRANSPARENT, TRANSPARENT, 3,
  286.      TRANSPARENT, NO_DRAW, 4, TRANSPARENT,
  287.      TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
  288.      TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT},
  289.     {0, TRANSPARENT, 1, NO_DRAW, TRANSPARENT,
  290.      NO_DRAW, NO_DRAW, NO_DRAW, 2, 3,
  291.      4, 0, TRANSPARENT, TRANSPARENT, TRANSPARENT,
  292.      TRANSPARENT, NO_DRAW, 1, NO_DRAW, 2}};
  293.  
  294. @implementation PolyhedraView
  295.  
  296. // Distance between two points.  Inlined for efficiency.
  297. inline float distance(NXCoord xcrd, NXCoord ycrd, NXCoord zcrd);
  298.  
  299. inline float distance(NXCoord xcrd, NXCoord ycrd, NXCoord zcrd)
  300. {
  301.     return sqrt(xcrd * xcrd + ycrd * ycrd + zcrd * zcrd);
  302. }
  303.  
  304. // Draw a line in the proper perspectice projection from pt1 to pt2
  305. - perspectiveLineFrom:(D3_PT)pt1 to:(D3_PT)pt2
  306. {
  307.     if (perspectivePt.z == 0)
  308.         return self;
  309.     PSmoveto(pt1.x - pt1.z * (pt1.x - perspectivePt.x) / perspectivePt.z,
  310.              pt1.y - pt1.z * (pt1.y - perspectivePt.y) / perspectivePt.z);
  311.     PSlineto(pt2.x - pt2.z * (pt2.x - perspectivePt.x) / perspectivePt.z,
  312.              pt2.y - pt2.z * (pt2.y - perspectivePt.y) / perspectivePt.z);
  313.     return self;
  314. }
  315.  
  316. // Draw the background room - in the appropriate gray.
  317. - drawBoxInColour:(float)theGray
  318. {
  319.     return self;    //by sam, I don't like the room!
  320.  
  321. #ifdef VANNA
  322.     D3_PT    pt1, pt2;
  323.     PSsetgray (theGray);
  324.     pt1.x = 0;
  325.     pt1.y = 0;
  326.     pt1.z = 0;
  327.     pt2.x = 0;
  328.     pt2.y = 0;
  329.     pt2.z = backTopRight.z;
  330.     [self perspectiveLineFrom:pt1 to:pt2];
  331.     pt1.z = backTopRight.z;
  332.     pt1.y = backTopRight.y;
  333.     [self perspectiveLineFrom:pt2 to:pt1];
  334.     pt2.z = 0;
  335.     pt2.y = backTopRight.y;
  336.     [self perspectiveLineFrom:pt1 to:pt2];
  337.     pt2 = backTopRight;
  338.     [self perspectiveLineFrom:pt1 to:pt2];
  339.     pt1.x = backTopRight.x;
  340.     pt1.z = 0;
  341.     [self perspectiveLineFrom:pt2 to:pt1];
  342.     pt1.y = 0;
  343.     pt1.z = backTopRight.z;
  344.     [self perspectiveLineFrom:pt2 to:pt1];
  345.     pt2.y = 0;
  346.     pt2.z = 0;
  347.     [self perspectiveLineFrom:pt1 to:pt2];
  348.     pt2.z = backTopRight.z;
  349.     pt2.x = 0;
  350.     [self perspectiveLineFrom:pt1 to:pt2];
  351.     PSstroke();
  352.     return self;
  353. #endif
  354. }
  355.  
  356. // Draw the polyhedron at the current position.
  357. - drawPolyhedron
  358. {
  359.     int        i, j, k, m, n=0;
  360.     float    faceVerticesZ[MAX_NUM_FACES][MAX_VERTICES_PER_FACE];
  361.     float    sortedVerticesZ[MAX_NUM_FACES][MAX_VERTICES_PER_FACE];
  362.     NXPoint    faceVerticesScreen[MAX_NUM_FACES][MAX_VERTICES_PER_FACE];
  363.     BOOL    drawn[MAX_NUM_FACES];
  364.     BOOL    intersect;
  365.     NXPoint    *thisFace, *tempFace, *firstVertex, *secondVertex, *thirdVertex, *fourthVertex;
  366.     int    colours[MAX_NUM_FACES];
  367.     float    r[MAX_NUM_FACES];
  368.     float    g[MAX_NUM_FACES];
  369.     float    b[MAX_NUM_FACES];
  370.     VERTEX    *thisVertex;
  371.     float    firstVertexZ, secondVertexZ, thirdVertexZ, fourthVertexZ;
  372.     float    det, s=0, t=0;
  373.     
  374.     // Pre-compute the positions of each of the vertices as they're drawn on the screen.  We'll need
  375.     // them a little later, and we'll keep them around until we erase this polyhedron from the screen.
  376.     for (i = 0; i < numVertices; i++)
  377.         {
  378.         thisVertex = vertices + i;
  379.         thisVertex->screenPos.x = perspectivePt.x + (thisVertex->pos.x - perspectivePt.x)  * perspectivePt.z / (perspectivePt.z + thisVertex->pos.z);
  380.         thisVertex->screenPos.y = perspectivePt.y + (thisVertex->pos.y - perspectivePt.y)  * perspectivePt.z / (perspectivePt.z + thisVertex->pos.z);
  381.         }
  382.     // Pick out the faces we have to draw, and grab an ordered list of the z-coordinates of each
  383.     // vertex in each face, for later on.
  384.     k = 0;
  385.     for (i = 0; i < numFaces; i++)
  386.         if (faceColour[polyhedron][i] != NO_DRAW)
  387.             {
  388.             for (j = 0; j < verticesPerFace; j++)
  389.                 {
  390.                 thisVertex = &( vertices[faces[polyhedron][i][j]]);
  391.                 faceVerticesScreen[k][j] = thisVertex -> screenPos;
  392.                 faceVerticesZ[k][j] = thisVertex->pos.z;
  393.                 for (m = 0; (m < j) && (sortedVerticesZ[k][m] > thisVertex->pos.z); m++)
  394.                     ;
  395.                 for (n = j; n > m; n--)
  396.                     sortedVerticesZ[k][n] = sortedVerticesZ[k][n - 1];
  397.                 sortedVerticesZ[k][m] = thisVertex->pos.z;
  398.                 }
  399.             colours[k] = faceColour[polyhedron][i];
  400.             if (colours[k] != TRANSPARENT)
  401.             {    
  402.                 r[k] = clut[colours[k]].r;
  403.                 g[k] = clut[colours[k]].g;
  404.                 b[k] = clut[colours[k]].b;
  405.             }
  406.             drawn[k] = NO;
  407.             k++;
  408.             }
  409.     // Now, run through the list of faces we have to draw, and select the next one to
  410.     // draw - by making sure that it's not in front of any faces we haven't drawn
  411.     // yet.
  412.     for (i = 0; i < numDrawFaces; i++)
  413.         {
  414.         for (k = 0; drawn[k]; k++)
  415.             ;
  416.         thisFace = (NXPoint *)&(faceVerticesScreen[k]);
  417.         for (j = k + 1; j < numDrawFaces; j++)
  418.             if (!drawn[j])
  419.                 {
  420.                 tempFace = (NXPoint *)&(faceVerticesScreen[j]);
  421.                 intersect = NO;
  422.                 // check for edges intersecting.
  423.                 for (m = 0; (!intersect) && (m < verticesPerFace); m++)
  424.                     for (n = 0; (!intersect) && (n < verticesPerFace); n++)
  425.                         {
  426.                         firstVertex = thisFace + m;
  427.                         secondVertex = (m + 1 == verticesPerFace) ? thisFace : thisFace + m + 1;
  428.                         thirdVertex = tempFace + n;
  429.                         fourthVertex = (n + 1 == verticesPerFace) ? tempFace : tempFace + n + 1;
  430.                         if (((firstVertex->x != thirdVertex->x) || (firstVertex->y != thirdVertex->y)) &&
  431.                            ((firstVertex->x != fourthVertex->x) || (firstVertex->y != fourthVertex->y)) &&
  432.                            ((secondVertex->x != thirdVertex->x) || (secondVertex->y != thirdVertex->y)) &&
  433.                            ((secondVertex->x != fourthVertex->x) || (secondVertex->y != fourthVertex->y)))
  434.                         if ((det = ((firstVertex->x - secondVertex->x) * (fourthVertex->y - thirdVertex->y) -
  435.                                    (firstVertex->y - secondVertex->y) * (fourthVertex->x - thirdVertex->x))) != 0)
  436.                             {
  437.                             t = ((fourthVertex->y - thirdVertex->y) * (fourthVertex->x - secondVertex->x) +
  438.                                  (thirdVertex->x - fourthVertex->x) * (fourthVertex->y - secondVertex->y)) / det;
  439.                             s = ((secondVertex->y - firstVertex->y) * (fourthVertex->x - secondVertex->x) +
  440.                                  (firstVertex->x - secondVertex->x) * (fourthVertex->y - secondVertex->y)) / det;
  441.                             if ((t > 0.0) && (t < 1.0) && (s > 0.0) & (s < 1.0))
  442.                                 intersect = YES;
  443.                             }
  444.                         }
  445.                 m --;
  446.                 n --;
  447.                 // if no edges intersect, order by z-coordinates.
  448.                 if (!intersect)
  449.                     {
  450.                     for (m = 0; (m < verticesPerFace) && (sortedVerticesZ[k][m] == sortedVerticesZ[j][m]); m++)
  451.                         ;
  452.                     if ((m != verticesPerFace) && (sortedVerticesZ[j][m] > sortedVerticesZ[k][m]))
  453.                         {
  454.                         k = j;
  455.                         thisFace = tempFace;
  456.                         }
  457. //                    else
  458. //                        ;
  459.                     }
  460.                 else
  461.                 // if there's a pair of edges intersecting, look at the z-coord at the
  462.                 // intersection pt - the largest z-coord is the one we drawn.
  463.                     {
  464.                     firstVertexZ = faceVerticesZ[k][m];
  465.                     secondVertexZ = (m + 1 == verticesPerFace) ? faceVerticesZ[k][0] :
  466.                                      faceVerticesZ[k][m + 1];
  467.                     thirdVertexZ = faceVerticesZ[j][n];
  468.                     fourthVertexZ = (n + 1 == verticesPerFace) ? faceVerticesZ[j][0] :
  469.                                      faceVerticesZ[j][n + 1];
  470.                     if (firstVertexZ * t + secondVertexZ * (1 - t) < thirdVertexZ * s + fourthVertexZ * (1 - s))
  471.                         {
  472.                         k = j;
  473.                         thisFace = tempFace;
  474.                         }
  475.                     }
  476.                 }
  477.                 
  478.  
  479.                 
  480.         // Let the wraps do the drawing, depending on the number of vertices in
  481.         // the face, and whether or not we should fill the face.
  482.         if (verticesPerFace == 3)
  483.             if (colours[k] != TRANSPARENT)
  484.                 colourTriangle(thisFace[0].x, thisFace[0].y, thisFace[1].x, thisFace[1].y,
  485.                                thisFace[2].x, thisFace[2].y, r[k],g[k],b[k]);
  486.             else
  487.                 outlineTriangle(thisFace[0].x, thisFace[0].y, thisFace[1].x, thisFace[1].y,
  488.                                 thisFace[2].x, thisFace[2].y);
  489.         else
  490.         if (verticesPerFace == 4)
  491.             if (colours[k] != TRANSPARENT)
  492.                 colourSquare(thisFace[0].x, thisFace[0].y, thisFace[1].x, thisFace[1].y,
  493.                              thisFace[2].x, thisFace[2].y, thisFace[3].x, thisFace[3].y,
  494.                              r[k],g[k],b[k]);
  495.             else
  496.                 outlineSquare(thisFace[0].x, thisFace[0].y, thisFace[1].x, thisFace[1].y,
  497.                               thisFace[2].x, thisFace[2].y, thisFace[3].x, thisFace[3].y);
  498.         else
  499.         if (verticesPerFace == 5)
  500.             if (colours[k] != TRANSPARENT)
  501.                 colourPentagon(thisFace[0].x, thisFace[0].y, thisFace[1].x, thisFace[1].y,
  502.                                thisFace[2].x, thisFace[2].y, thisFace[3].x, thisFace[3].y,
  503.                                thisFace[4].x, thisFace[4].y, r[k],g[k],b[k]);
  504.             else
  505.                 outlinePentagon(thisFace[0].x, thisFace[0].y, thisFace[1].x, thisFace[1].y,
  506.                                 thisFace[2].x, thisFace[2].y, thisFace[3].x, thisFace[3].y,
  507.                                 thisFace[4].x, thisFace[4].y);
  508.  
  509.         drawn[k] = YES;
  510.         }
  511.     
  512.     return self;    
  513. }
  514.  
  515.  
  516. // Erase the polyhedron.  Quick, and dirty - just erase a large rectangle that
  517. // covers the entire polyhedron on the screen - if it erase some of the background, so
  518. // what?  We'll redraw that in a little while, anyway.  This method has the prime virtue of
  519. // being fast, fast, fast.
  520. - erasePolyhedron
  521. {
  522.     int        i;
  523.     NXRect    eraseRect;
  524.     float    maxX, maxY, minX, minY;
  525.     NXPoint    thisPt;
  526.     
  527.     maxY = maxX = 0;
  528.     minX = frame.size.width;
  529.     minY = frame.size.height;
  530.     for (i = 0; i < numVertices; i++)
  531.         {
  532.         thisPt = vertices[i].screenPos;
  533.         if (thisPt.x > maxX)
  534.             maxX = thisPt.x;
  535.         if (thisPt.y > maxY)
  536.             maxY = thisPt.y;
  537.         if (thisPt.x < minX)
  538.             minX = thisPt.x;
  539.         if (thisPt.y < minY)
  540.             minY = thisPt.y;
  541.         }
  542.     
  543.     eraseRect.origin.x = minX;
  544.     eraseRect.origin.y = minY;
  545.     eraseRect.size.width = maxX - minX + 1;
  546.     eraseRect.size.height = maxY - minY + 1;
  547.     PSsetgray(NX_BLACK);
  548.     NXRectFill(&eraseRect);
  549.     return self;    
  550. }
  551.  
  552. // Do one animation step.
  553. - oneStep
  554. {
  555.     int        i, j;
  556.     float    length;
  557.     float    dotProduct;
  558.     D3_PT    velForce[MAX_NUM_VERTICES], force[MAX_NUM_VERTICES];
  559.     float    theForce;
  560.     D3_PT    sumVel;
  561.  
  562.     // Cycle the background box colours.
  563.     if (((backStep ++) % 20) == 0)
  564.         {
  565.         switch (backStep / 20)
  566.             {
  567. #ifdef VANNA
  568.             case 0:
  569.                 [self drawBoxInColour:NX_WHITE];
  570.                 break;
  571.             case 1:
  572.                 [self drawBoxInColour:NX_LTGRAY];
  573.                 break;
  574.             case 2:
  575.                 [self drawBoxInColour:NX_DKGRAY];
  576.                 break;
  577.             case 3:
  578.                 [self drawBoxInColour:NX_BLACK];
  579.                 break;
  580. #endif
  581.             default:
  582.                 // Compute average velocity of icosahedron
  583.                 // If it's too small, give it a random kick
  584.                 sumVel.x = sumVel.y = sumVel.z = 0;
  585.                 for (i = 0; i < numVertices; i++)
  586.                     {
  587.                     sumVel.x += vertices[i].vel.x;
  588.                     sumVel.y += vertices[i].vel.y;
  589.                     sumVel.z += vertices[i].vel.z;
  590.                     }
  591.                 if (distance(sumVel.x, sumVel.y, sumVel.z) / numVertices < 0.5) //.33
  592.                     {
  593.                     sumVel.x = randBetween(-INIT_VELOCITY, INIT_VELOCITY);
  594.                     sumVel.y = randBetween(-INIT_VELOCITY, INIT_VELOCITY);
  595.                     sumVel.z = randBetween(-INIT_VELOCITY, INIT_VELOCITY);
  596.                     for (i = 0; i < numVertices; i++)
  597.                         {
  598.                         vertices[i].vel.x += sumVel.x;
  599.                         vertices[i].vel.y += sumVel.y;
  600.                         vertices[i].vel.z += sumVel.z;
  601.                         }
  602.                     }
  603.                 backStep = 0;
  604.                 break;
  605.             }
  606.         }
  607.     // If we're not doing anything about the polyhedron, leave now.
  608.     if (noAnimation)
  609.         return self;
  610.     // Erase it.
  611.     [self erasePolyhedron];
  612.     // Move it, bouncing off walls as necessary
  613.     for (i = 0; i < numVertices; i++)
  614.         {
  615.         vertices[i].pos.x += vertices[i].vel.x;
  616.         if ((vertices[i].pos.x < 0) || (vertices[i].pos.x > backTopRight.x))
  617.             vertices[i].vel.x = -vertices[i].vel.x;
  618.         vertices[i].pos.y += vertices[i].vel.y;
  619.         if ((vertices[i].pos.y < 0) || (vertices[i].pos.y > backTopRight.y))
  620.             vertices[i].vel.y = -vertices[i].vel.y;
  621.         vertices[i].pos.z += vertices[i].vel.z;
  622.         if ((vertices[i].pos.z < 0) || (vertices[i].pos.z > backTopRight.z))
  623.             vertices[i].vel.z = -vertices[i].vel.z;
  624.         }
  625.     // draw it
  626.     [self drawPolyhedron];
  627.     for (i = 0; i < numVertices; i++)
  628.         {
  629.         velForce[i].x = force[i].x = 0;
  630.         velForce[i].y = force[i].y = 0;
  631.         velForce[i].z = force[i].z = 0;
  632.         }
  633.     // calculate the force on each vertex.
  634.     // Notice the use of symmetry here to cut down the amount of computation
  635.     // i.e. the force on vertex j exerted by the spring from vertex i is minus
  636.     //      that on vertex i exerted by vertex j .....
  637.     for (i = 0; i < numVertices; i++)
  638.         {
  639.         for (j = i + 1; j < numVertices; j++)
  640.             {
  641.             // spring forces (Hookes' Law - remember that?)
  642.             length = distance(vertices[i].pos.x - vertices[j].pos.x,
  643.                           vertices[i].pos.y - vertices[j].pos.y,
  644.                           vertices[i].pos.z - vertices[j].pos.z);
  645.             theForce = (vertices[i].pos.x - vertices[j].pos.x) / length * (restLengths[i][j] - length) * SPRING_K;
  646.             force[i].x += theForce;
  647.             force[j].x -= theForce;
  648.             theForce = (vertices[i].pos.y - vertices[j].pos.y) / length * (restLengths[i][j] - length) * SPRING_K;
  649.             force[i].y += theForce;
  650.             force[j].y -= theForce;
  651.             theForce = (vertices[i].pos.z - vertices[j].pos.z) / length * (restLengths[i][j] - length) * SPRING_K;
  652.             force[i].z += theForce;
  653.             force[j].z -= theForce;
  654.             
  655.             // Velocity damping - only for adjacent vertices
  656.             
  657.             if (isAdjacent[i][j])
  658.                 {
  659.                 dotProduct = ((vertices[i].pos.x - vertices[j].pos.x) * (vertices[i].vel.x - vertices[j].vel.x) +
  660.                               (vertices[i].pos.y - vertices[j].pos.y) * (vertices[i].vel.y - vertices[j].vel.y) +
  661.                               (vertices[i].pos.z - vertices[j].pos.z) * (vertices[i].vel.z - vertices[j].vel.z)) / length/length * damping;
  662.                 
  663.                 theForce = dotProduct * (vertices[i].pos.x - vertices[j].pos.x);
  664.                 velForce[i].x -= theForce;
  665.                 velForce[j].x += theForce;
  666.                 theForce = dotProduct * (vertices[i].pos.y - vertices[j].pos.y);
  667.                 velForce[i].y -= theForce;
  668.                 velForce[j].y += theForce;
  669.                 theForce = dotProduct * (vertices[i].pos.z - vertices[j].pos.z); //xxx
  670.                 velForce[i].z -= theForce;
  671.                 velForce[j].z += theForce;
  672.                 }
  673.             }
  674.         }
  675.     // Change the velocities (F = ma !!).  Make sure the velocities don't get too big.
  676.     // (Stability check).
  677.     for (i = 0; i < numVertices; i++)
  678.         {
  679.         vertices[i].vel.x += (velForce[i].x + force[i].x) / vertices[i].mass;
  680.         if (fabs(vertices[i].vel.x) > MAX_VEL)
  681.             vertices[i].vel.x = vertices[i].vel.x / fabs(vertices[i].vel.x) * MAX_VEL;
  682.         vertices[i].vel.y += (velForce[i].y + force[i].y) / vertices[i].mass;
  683.         if (fabs(vertices[i].vel.y) > MAX_VEL)
  684.             vertices[i].vel.y = vertices[i].vel.y / fabs(vertices[i].vel.y) * MAX_VEL;
  685.         vertices[i].vel.z += (velForce[i].z + force[i].z) / vertices[i].mass;
  686.         if (fabs(vertices[i].vel.z) > MAX_VEL)
  687.             vertices[i].vel.z = vertices[i].vel.z / fabs(vertices[i].vel.z) * MAX_VEL;
  688.         }
  689.     return self;
  690. }
  691.  
  692. // Just erase ourself.
  693. - drawSelf:(const NXRect *)rects :(int)rectCount
  694. {
  695.     if (!rects || !rectCount)
  696.         return self;
  697.  
  698.     PSsetlinewidth(0);
  699.     PSsetgray(0);
  700.     NXRectFill(rects);
  701.     
  702.     return self;
  703. }
  704.  
  705. // Somebody just changed the size of the box we're sitting in - recompute
  706. // stuff, and start the animation again.
  707. - frameChanged:(const NXRect *)frameRect
  708. {
  709.     D3_PT    initPos, initVel;
  710.     int        i, j;
  711.     float    length;
  712.     
  713.     [self useNewFrame:frameRect];
  714.  
  715.     // Compute the room size.
  716.     backTopRight.x = frameRect->size.width;
  717.     backTopRight.y = frameRect->size.height;
  718.     backTopRight.z = frameRect->size.height;
  719.     
  720.     // Where the perspective's coming from.
  721.     perspectivePt.x = backTopRight.x / 2;
  722.     perspectivePt.y = backTopRight.y / 2;
  723.     perspectivePt.z = backTopRight.y * DEPTH;
  724.     
  725.     // Compute initial velocity.
  726.     initVel.x = randBetween(-INIT_VELOCITY, INIT_VELOCITY);
  727.     initVel.y = randBetween(-INIT_VELOCITY, INIT_VELOCITY);
  728.     initVel.z = randBetween(-INIT_VELOCITY, INIT_VELOCITY);
  729.     
  730.     // If the room's too small, we're going to have problems, so don't
  731.     // stick the polyhedron in.
  732.     if ((frameRect->size.width < 240) || (frameRect->size.height < 240))
  733.         noAnimation = YES;
  734.     else
  735.         {
  736.         noAnimation = NO;
  737.         
  738.         // Compute initial position.
  739.         initPos.x = randBetween(120, frameRect->size.width - 120);
  740.         initPos.y = randBetween(120, frameRect->size.height - 120);
  741.         initPos.z = randBetween(120, frameRect->size.height - 120);
  742.         
  743.         // Compute the rest lengths of the springs.
  744.         length = distance(offsets[polyhedron][0].x - offsets[polyhedron][1].x, offsets[polyhedron][0].y - offsets[polyhedron][1].y, offsets[polyhedron][0].z - offsets[polyhedron][1].z);
  745.         for (i = 0; i < numVertices; i++)
  746.             {
  747.             vertices[i].pos.x = initPos.x + offsets[polyhedron][i].x * SPRING_REST_LEN / length;
  748.             vertices[i].pos.y = initPos.y + offsets[polyhedron][i].y * SPRING_REST_LEN / length;
  749.             vertices[i].pos.z = initPos.z + offsets[polyhedron][i].z * SPRING_REST_LEN / length;
  750.             vertices[i].vel  = initVel;
  751.             }
  752.         for (i = 0; i < numVertices; i++)
  753.             for (j = 0; j < numVertices; j++)
  754.                 {
  755.                 length = distance(vertices[i].pos.x - vertices[j].pos.x, vertices[i].pos.y - vertices[j].pos.y,
  756.                                vertices[i].pos.z - vertices[j].pos.z);
  757.                 restLengths[i][j] = length;
  758.                 }
  759.         }
  760.     
  761.     // Compute the damping factor
  762.     
  763.     damping = DAMPING * realAdjacents / numVertices;
  764.     
  765.     // sanity check:  if this number is too big, then velocity
  766.     // damping contributes to instability, rather than curing it...
  767.     
  768.     if (damping > 0.3)
  769.         damping = 0.3;
  770.         
  771.     return self;
  772. }
  773.  
  774.  
  775. // If we get either setFrame, or sizeTo messages, we'd better recompute the
  776. // box and stuff.
  777. - setFrame:(const NXRect *)frameRect
  778. {
  779.     [super setFrame:frameRect];
  780.     
  781.     [self frameChanged: frameRect];
  782.     
  783.     return self;
  784. }
  785.  
  786. - sizeTo:(NXCoord)width :(NXCoord)height
  787. {
  788.     NXRect frameRect;
  789.     
  790.     [super sizeTo:width:height];
  791.     
  792.     frameRect.origin.x = 0;
  793.     frameRect.origin.y = 0;
  794.     
  795.     frameRect.size.width = width;
  796.     frameRect.size.height = height;
  797.  
  798.     [self frameChanged: &frameRect];
  799.  
  800.     return self;
  801. }
  802.  
  803. - initFrame:(const NXRect *)frameRect
  804. {
  805.     [super initFrame: frameRect];
  806.     
  807.     [self useNewFrame:frameRect];
  808.  
  809.     if (frameRect != NULL)
  810.         [self setFrame:frameRect];
  811.  
  812.     return self;
  813. }
  814.  
  815. - useNewFrame:(const NXRect *)frameRect
  816. {
  817.     int        i, j, k;
  818.     D3_PT    initVel;
  819.     BOOL    foundVertex;
  820.     
  821.     // Decide which Polyhedron.
  822.     if (selectedIndex == 0)    polyhedron   = random() % 5;
  823.     else    polyhedron = selectedIndex-1;
  824.  
  825.     numVertices  = theNumVertices[polyhedron];
  826.     numAdjacents = theNumAdjacents[polyhedron];
  827.     numFaces     = theNumFaces[polyhedron];
  828.     numDrawFaces = realFaces[polyhedron];
  829.     verticesPerFace = theVerticesPerFace[polyhedron];
  830.     
  831.     // Compute adjacency info.
  832.     // Notice that for the purposes of velocity damping, adjacent 
  833.     // is the same as "are vertices on the same face." Not "are
  834.     // vertices on the same edge."
  835.     for (i = 0; i < numVertices; i++)
  836.         {
  837.         for (j = 0; j < numVertices; j++)
  838.             isAdjacent[i][j] = NO;
  839.         for (j = 0; j < numFaces; j++)
  840.             {
  841.             foundVertex = NO;
  842.             for (k = 0; k < verticesPerFace; k++)
  843.                 if (faces[polyhedron][j][k] == i)
  844.                     foundVertex = YES;
  845.             if (foundVertex)
  846.                 for (k = 0; k < verticesPerFace; k++)
  847.                     if (faces[polyhedron][j][k] != i)
  848.                         isAdjacent[i][faces[polyhedron][j][k]] = YES;
  849.             }
  850.         }
  851.     
  852.     realAdjacents = 0;
  853.     for (i = 0; i < numVertices; i++)
  854.          if (isAdjacent[0][i])
  855.             realAdjacents ++;
  856.             
  857.     backTopRight.x = 0;
  858.     backTopRight.y = 0;
  859.     backTopRight.z = 0;
  860.     
  861.     perspectivePt.x = 0;
  862.     perspectivePt.y = 0;
  863.     perspectivePt.z = 0;
  864.     
  865.     noAnimation = YES;
  866.     initVel.x = randBetween(-INIT_VELOCITY, INIT_VELOCITY);
  867.     initVel.y = randBetween(-INIT_VELOCITY, INIT_VELOCITY);
  868.     initVel.z = randBetween(-INIT_VELOCITY, INIT_VELOCITY);
  869.     
  870.     // set up the initial position of the icosahedron.
  871.     
  872.     for (i = 0; i < numVertices; i++)
  873.         {
  874.         vertices[i].mass = MASS;
  875.         vertices[i].vel  = initVel;
  876.         }
  877.     
  878.     backStep = 0;
  879.     
  880.     damping = DAMPING;
  881.     
  882.       return self;
  883. }
  884.  
  885. - setSelectedIndex:sender
  886. {
  887.     int val;
  888.     val = [sender selectedRow];
  889.     if (selectedIndex == val) return self;
  890.  
  891.     selectedIndex = val;
  892.     [self frameChanged: &bounds];
  893.     [self display];
  894.     return self;
  895. }
  896.  
  897. - kickIt:sender
  898. {
  899.     int i;
  900.     float    x,y,z;
  901.  
  902.     x = randBetween(-INIT_VELOCITY, INIT_VELOCITY);
  903.     y = randBetween(-INIT_VELOCITY, INIT_VELOCITY);
  904.     z = randBetween(-INIT_VELOCITY, INIT_VELOCITY);
  905.  
  906.     for (i = 0; i < numVertices; i++)
  907.     {
  908.         vertices[i].vel.x += x;
  909.         vertices[i].vel.y += y;
  910.         vertices[i].vel.z += z;
  911.     }
  912.     return self;
  913. }
  914.  
  915. - inspector:sender
  916. {
  917.     char buf[MAXPATHLEN];
  918.     
  919.     if (!inspectorPanel)
  920.     {
  921.         sprintf(buf,"%s/Polyhedra.nib",[sender moduleDirectory:"Polyhedra"]);
  922.         [NXApp loadNibFile:buf owner:self withNames:NO];
  923.     }
  924.     return inspectorPanel;
  925. }
  926.  
  927. - (BOOL) useBufferedWindow
  928. {    return YES;
  929. }
  930.  
  931.  
  932.  
  933. @end
  934.